package com.bluebridgecup.BasicAlgorithms.oneDimensionPrefixSumAndDifference;

import java.util.Scanner;

public class CharacterShiftOperator {
    public static void main(String[] args) {
        // 创建Scanner对象用于读取用户输入
        Scanner sc = new Scanner(System.in);

        // 读取字符串的长度n
        int n = sc.nextInt();
        // 读取操作的次数q
        int q = sc.nextInt();
        // 消耗掉之前输入操作留下的换行符，确保后续读取字符串的准确性
        sc.nextLine();
        // 读取原始字符串s
        String s = sc.nextLine();

        // 创建一个长度为n + 2的数组b，用于记录每个位置字符的偏移量变化（差分操作）
        int[] b = new int[n + 2];

        // 循环q次，执行q次操作
        for (int i = 0; i < q; i++) {
            // 读取每次操作的左边界l
            int l = sc.nextInt();
            // 读取每次操作的右边界r
            int r = sc.nextInt();
            // 读取每次操作的右移字符数k
            int k = sc.nextInt();

            // 计算实际的右移量t，对26取模，因为字母表有26个字母，偏移量会循环
            int t = k % 26;
            // 在左边界l处增加右移量t，记录该位置偏移量变化
            b[l] += t;
            // 在右边界r + 1处减去右移量t，通过差分方式记录偏移量变化，以便后续前缀和计算
            b[r + 1] -= t;
        }

        // 创建一个长度为n + 1的数组a，用于存储前缀和，即每个位置的累计偏移量
        int[] a = new int[n + 1];
        // 计算前缀和数组a，通过累加b数组的值得到每个位置的累计偏移量
        for (int i = 1; i <= n; i++) {
            a[i] = a[i - 1] + b[i];
        }

        // 创建一个StringBuilder对象ans，用于构建最终的结果字符串
        StringBuilder ans = new StringBuilder();
        // 遍历字符串s的每个字符
        for (int i = 1; i <= n; i++) {
            // 获取字符串s中第i - 1个字符
            char ch = s.charAt(i - 1);
            // 获取字符i处的总右移次数（对26取模，确保偏移量在有效范围内）
            int chh = a[i] % 26;
            // 计算经过右移操作后的新字符
            // 先将字符ch转换为字母表中的偏移量，加上偏移量chh，再处理可能出现的负数情况（加26），
            // 然后对26取模保证偏移量在0 - 25之间，最后再转换回字符
            char c = (char) ((ch - 'a' + chh + 26) % 26 + 'a');
            // 将新字符c添加到结果字符串ans中
            ans.append(c);
        }
        // 输出最终经过右移操作后的字符串
        System.out.println(ans.toString());
        // 关闭Scanner对象，释放资源
        sc.close();
    }
}